﻿using System;
using System.IO;
namespace tuimg.helpers
{
    using tuimg.element;
    using tuimg.structs;
    using SanlieHash.OtherHash;
    using System.IO.Compression;

    internal partial class helper
    {
        internal static CRC32 crc = new CRC32();
        public static uint calc_crc(Stream sr, long pos, uint length)
        {
            sr.Position = pos;
            crc.New();
            var buf = new byte[1024];
            var len = length >> 10;
            for (; len > 0; len --)
            {
                sr.Read(buf, 0, 1024);
                crc.Update(buf);
            }
            if ((len = length & 1023) > 0)
            {
                buf = new byte[len];
                sr.Read(buf, 0, (int)len);
                crc.Update(buf);
            }

            return crc.MakeUInt32();
        }
        public static void ReadAllToMemory(Stream sr, Stream dst)
        {
            var buf = new byte[1024];
            int len = 1;
            while (sr.CanRead && len!=0) if ((len = sr.Read(buf, 0, 1024)) > 0) dst.Write(buf, 0, len);
            dst.Flush();
        }
        public static void ReadToMemory(Stream sr, Stream dst, uint len)
        {
            var buf = new byte[1024];
            var len2 = len >> 10;
            var len3 = 1024;

            for(; len2 > 0; len2--) if ((len3 = sr.Read(buf, 0, 1024))>0) dst.Write(buf, 0, len3);

            len3 = (int)(len & 1023);
            if (len3 > 0)
            {
                len3 = sr.Read(buf, 0, len3);
                dst.Write(buf, 0, len3);
            }
            dst.Flush();
        }
        public static uint Readuint(Stream sr)
        {
            return (uint)Readint(sr);
        }
        public static int Readint(Stream sr)
        {
            return Readushort(sr) | (int)Readushort(sr)<<16;
        }
        public static string Readchars(Stream sr, int count)
        {
            var text = string.Empty;
            for (; count > 0; count--) text += (char)sr.ReadByte();
            return text;
        }
        public static void Writechars(Stream sr, string chars)
        {
            foreach (var _char in chars) sr.WriteByte((byte)_char);
        }
        public static uint Readuint2(Stream sr)
        {
            return (uint)Readushort2(sr)<<16 | Readushort2(sr);
        }
        public static ulong Readulong2(Stream sr)
        {
            return (ulong)(Readuint2(sr)) << 32 | Readuint2(sr);
        }
        public static ulong Readulong(Stream sr)
        {
            return Readuint(sr) | (ulong)Readuint(sr) << 32;
        }
        public static short Readshort(Stream sr)
        {
            return (short)(sr.ReadByte() | sr.ReadByte() << 8);
        }
        public static ushort Readushort(Stream sr)
        {
            return (ushort)Readshort(sr);
        }
        public static ushort Readushort2(Stream sr)
        {
            return (ushort)Readshort2(sr);
        }
        public static short Readshort2(Stream sr)
        {
            return (short)(sr.ReadByte() << 8 | sr.ReadByte());
        }
        public static decimal Read16Dot16(Stream sr)
        {
            var a = Readushort2(sr);
            var b = Readushort2(sr);
            while (b > 0) b /= 10;
            return a + b;
        }
        public static byte Readbyte(Stream sr)
        {
            return (byte)sr.ReadByte();
        }
        public static TuimgColor ReadColor24(Stream sr)
        {
            return TuimgColor.FromRgb((byte)sr.ReadByte(), (byte)sr.ReadByte(), (byte)sr.ReadByte());
        }
        public static TuimgColor ReadColor32(Stream sr)
        {
            return TuimgColor.FromRgb((byte)sr.ReadByte(), (byte)sr.ReadByte(), (byte)sr.ReadByte(), (byte)sr.ReadByte());
        }
        public static TuimgColor ReadColor24Bgr(Stream sr)
        {
            return TuimgColor.FromBgr((byte)sr.ReadByte(), (byte)sr.ReadByte(), (byte)sr.ReadByte());
        }
        public static TuimgColor ReadColor32Bgra(Stream sr)
        {
            return TuimgColor.FromBgra((byte)sr.ReadByte(), (byte)sr.ReadByte(), (byte)sr.ReadByte(), (byte)sr.ReadByte());
        }
        public static TuimgColor ReadColor32Bgr_reserved(Stream sr)
        {
            return TuimgColor.FromBgr_reserved((byte)sr.ReadByte(), (byte)sr.ReadByte(), (byte)sr.ReadByte(), (byte)sr.ReadByte());
        }
        public static TuimgColor ReadColor8(Stream sr)
        {
            return TuimgColor.From8((byte)sr.ReadByte());
        }
        public static TuimgColor ReadColor16(Stream sr)
        {
            return TuimgColor.From16((byte)sr.ReadByte(), (byte)sr.ReadByte());
        }
        public static TuimgColor ReadColorBgr(Stream sr, short bitcount)
        {
            switch (bitcount)
            {
                case 32: return ReadColor32Bgra(sr);
                case 24: return ReadColor24Bgr(sr);
                case 16: return ReadColor16(sr);
                case 8: return ReadColor8(sr);
            }
            return TuimgColor.SkyBlue;
        }
        public static TuimgColor ReadColor(Stream sr, short bitcount)
        {
            switch (bitcount)
            {
                case 32: return ReadColor32(sr);
                case 24: return ReadColor24(sr);
                case 16: return ReadColor16(sr);
                case 8: return ReadColor8(sr);
            }
            return TuimgColor.SkyBlue;
        }
        public static bool IsTransparent(Stream sr, short bitcount, int transport=0)
        {
            if (bitcount < 32) return false;
            sr.Position += 3;
            return sr.ReadByte() > transport;
        }
        public static TuimgColor ReadColor(Stream sr, short bitcount, TuimgColor background)
        {
            switch (bitcount)
            {
                case 32: return ReadColor32(sr, background);
                case 24: return ReadColor24(sr);
            }
            return TuimgColor.SkyBlue;
        }
        public static TuimgColor ReadColor32(Stream sr, TuimgColor background)
        {
            return TuimgColor.FromRgb((byte)sr.ReadByte(), (byte)sr.ReadByte(), (byte)sr.ReadByte(), (byte)sr.ReadByte(), background.r, background.g, background.b);
        }
        public static void Write(Stream sr, byte value)
        {
            sr.WriteByte(value);
        }
        internal static void write_crc(Stream sr, long start, uint length)
        {
            uint crc = calc_crc(sr, start, length);
            Write(sr, crc);
        }
        public static void WriteColor(Stream sr, double color, int bitcount)
        {
            var bytes  = BitConverter.GetBytes((int)color);
            if (bitcount >= 32) helper.Write(sr, bytes[3]);
            if (bitcount >= 24) helper.Write(sr, bytes[2]);
            if (bitcount >= 16) helper.Write(sr, bytes[2]);
            if (bitcount >= 8) helper.Write(sr, bytes[2]);
        }
        public static void Write(Stream sr, uint value)
        {
            sr.WriteByte((byte)value);
            sr.WriteByte((byte)(value>>8));
            sr.WriteByte((byte)(value>>16));
            sr.WriteByte((byte)(value>>24));
        }
        public static void Write2(Stream sr, uint value)
        {
            sr.WriteByte((byte)(value >> 24));
            sr.WriteByte((byte)(value >> 16));
            sr.WriteByte((byte)(value >> 8));
            sr.WriteByte((byte)value);
        }
        public static void Write(Stream sr, ushort value)
        {
            sr.WriteByte((byte)value);
            sr.WriteByte((byte)(value >> 8));
        }
        public static void Write2(Stream sr, ushort value)
        {
            sr.WriteByte((byte)(value >> 8));
            sr.WriteByte((byte)value);
        }
        public static void Write(Stream sr, int value)
        {
            sr.WriteByte((byte)value);
            sr.WriteByte((byte)(value >> 8));
            sr.WriteByte((byte)(value >> 16));
            sr.WriteByte((byte)(value >> 24));
        }
        public static void Write2(Stream sr, int value)
        {
            sr.WriteByte((byte)(value >> 24));
            sr.WriteByte((byte)(value >> 16));
            sr.WriteByte((byte)(value >> 8));
            sr.WriteByte((byte)value);
        }
        public static void Write(Stream sr, ulong value)
        {
            sr.WriteByte((byte)value);
            sr.WriteByte((byte)(value >> 8));
            sr.WriteByte((byte)(value >> 16));
            sr.WriteByte((byte)(value >> 24));
            sr.WriteByte((byte)(value >> 32));
            sr.WriteByte((byte)(value >> 40));
            sr.WriteByte((byte)(value >> 48));
            sr.WriteByte((byte)(value >> 56));
        }
        public static void Write2(Stream sr, ulong value)
        {
            sr.WriteByte((byte)(value >> 56));
            sr.WriteByte((byte)(value >> 48));
            sr.WriteByte((byte)(value >> 40));
            sr.WriteByte((byte)(value >> 32));
            sr.WriteByte((byte)(value >> 24));
            sr.WriteByte((byte)(value >> 16));
            sr.WriteByte((byte)(value >> 8));
            sr.WriteByte((byte)value);
        }
        public static void Write(Stream sr, struct_32bit_color color)
        {
            sr.WriteByte(color.B);
            sr.WriteByte(color.G);
            sr.WriteByte(color.R);
            sr.WriteByte(color.A);
        }
        public static void Write(Stream sr, struct_24bit_color color)
        {
            sr.WriteByte(color.B);
            sr.WriteByte(color.G);
            sr.WriteByte(color.R);
        }
        public static void Write(Stream sr, struct_16bit_color color)
        {
            sr.WriteByte(color.color1);
            sr.WriteByte(color.color2);
        }
        public static void Write(Stream sr, struct_8bit_color color)
        {
            sr.WriteByte(color.color);
        }
        public static void WriteRgb(Stream sr, struct_32bit_color color)
        {
            sr.WriteByte(color.R);
            sr.WriteByte(color.G);
            sr.WriteByte(color.B);
            sr.WriteByte(color.A);
        }
        public static void WriteRgb(Stream sr, struct_24bit_color color)
        {
            sr.WriteByte(color.R);
            sr.WriteByte(color.G);
            sr.WriteByte(color.B);
        }
        public static void WriteRgb(Stream sr, struct_16bit_color color)
        {
            sr.WriteByte(color.color1);
            sr.WriteByte(color.color2);
        }
        public static void WriteRgb(Stream sr, struct_8bit_color color)
        {
            sr.WriteByte(color.color);
        }
        public static void WriteColor(Stream sr, object color)
        {
            if (color is struct_8bit_color color_8bit) Write(sr, color_8bit);
            else if (color is struct_16bit_color color_16bit) Write(sr, color_16bit);
            else if (color is struct_24bit_color color_24bit) Write(sr, color_24bit);
            else if (color is struct_32bit_color color_32bit) Write(sr, color_32bit);
        }
        public static void WriteColorRgb(Stream sr, object color)
        {
            if (color is struct_8bit_color color_8bit) WriteRgb(sr, color_8bit);
            else if (color is struct_16bit_color color_16bit) WriteRgb(sr, color_16bit);
            else if (color is struct_24bit_color color_24bit) WriteRgb(sr, color_24bit);
            else if (color is struct_32bit_color color_32bit) WriteRgb(sr, color_32bit);
        }
        public static void deflate_decompress(Stream s, Stream dst)
        {
            s.Seek(0, SeekOrigin.Begin);
            using (var df = new DeflateStream(s, CompressionMode.Decompress, true)) helper.ReadAllToMemory(df, dst);
        }
        public static void defalte_compress(Stream s, Stream dst)
        {
            s.Seek(0, SeekOrigin.Begin);
            using (var df = new DeflateStream(dst, CompressionMode.Compress, true)) helper.ReadAllToMemory(s, df);
            dst.Seek(0, SeekOrigin.Begin);
        }

        public static string read_image_type(Stream s)
        {
            var longtag = helper.Readulong(s);
            s.Position -= 8;
            if (TuimgPng.png_tag == longtag) return "png";
            if (TuimgBmp.bmp_tag == (longtag & 0xffff)) return "bmp";
            if (TuimgIco.ico_tag == (longtag & 0xffffffff)) return "ico";
            if (TuimgJpeg.jpeg_tag == (longtag & 0xffffffff)) return "jpeg";

            return string.Empty;
        }
    }
}
